import Vue, {PropType} from "vue";
import gsap from "gsap";

interface LsDialogPanelDataType {
  /** bind **/
  draggableFlag: boolean,
  enterClass: string,
  leaveClass: string,
  /** unbind **/
  fullScreenFlag?: boolean,
  draggableDom?: DraggableDom
  originalX?: string,
  originalY?: string,
  originalHeight?: string,
  originalWidth?: string,
}

interface LsDialogPanelMethodsType {
  toggleFullScreen(): void,

  confirm(): void,

  setSize(): void,

  sizeChange(): void

  initSize(): void
}

interface LsDialogPanelPropsType {
  titleText: string,
  width: string,
  fullScreen: boolean,
  showFullScreen: boolean,
  closeConfirm: boolean,
  closeTip: string,
  closeDialog: (type: 'byButton' | 'byModal' | 'byKey') => Promise<void>,
  draggable: boolean,
  fitHeight: boolean,
  height: string,
  //是否显示在外层相对盒子的中央，default: true
  boxCenter: boolean,
  //当boxCenter为false时，left的值，default: 'unset'
  left: string
  //当boxCenter为false时，top的值，default: 'unset'
  top: string
  //当boxCenter为false时，right的值，default: 'unset'
  right: string
  //当boxCenter为false时，bottom的值，default: 'unset'
  bottom: string
  //是否显示脚部按钮区域
  showFooter: boolean,
}

export default Vue.extend<LsDialogPanelDataType, LsDialogPanelMethodsType, unknown, LsDialogPanelPropsType>({
  name: "LsDialogPanel",
  props: {
    titleText: {
      type: String,
      required: true
    },
    width: {
      type: String,
      required: true
    },
    fullScreen: {
      type: Boolean,
      required: true
    },
    showFullScreen: {
      type: Boolean,
      required: true
    },
    closeConfirm: {
      type: Boolean,
      required: true
    },
    closeTip: {
      type: String,
      required: true
    },
    closeDialog: {
      type: Function as PropType<(type: 'byButton' | 'byModal' | 'byKey') => Promise<void>>,
      required: true
    },
    draggable: {
      type: Boolean,
      required: true
    },
    fitHeight: {
      type: Boolean,
      required: true
    },
    height: {
      type: String,
      required: true
    },
    boxCenter: {
      type: Boolean,
      default: true
    },
    //当boxCenter为false时，left的值，default: 'unset'
    left: {
      type: String,
      default: 'unset'
    },
    //当boxCenter为false时，top的值，default: 'unset'
    top: {
      type: String,
      default: 'unset'
    },
    //当boxCenter为false时，right的值，default: 'unset'
    right: {
      type: String,
      default: 'unset'
    },
    //当boxCenter为false时，bottom的值，default: 'unset'
    bottom: {
      type: String,
      default: 'unset'
    },
    showFooter: {
      type: Boolean,
      default: true
    }
  },
  mounted() {
    this.fullScreenFlag = this.fullScreen;
    const el = this.$el as HTMLElement;
    if (this.boxCenter) {
      el.style.left = '50%';
      el.style.top = '50%';
    } else {
      el.style.left = this.left;
      el.style.top = this.top;
      el.style.bottom = this.bottom;
      el.style.right = this.right;
    }
    if (this.fullScreenFlag) {
      el.style.width = '100%';
      el.style.height = '100%';
    } else {
      el.style.width = this.width;
      el.style.height = this.height;
    }
    if (this.draggable) {
      this.draggableDom = new DraggableDom(this.$el as HTMLElement, this.$refs.triggerDom as HTMLElement, this.boxCenter);
      this.draggableDom.start();
      if (this.fullScreenFlag) {
        this.draggableFlag = false;
        this.draggableDom.setPause(true);
      }
    }
  },
  beforeDestroy() {
    if (this.draggableDom)
      this.draggableDom.stop();
  },
  data() {
    return {
      draggableFlag: this.draggable,
      enterClass: 'animate__animated animate__zoomIn animate__faster' + (this.boxCenter ? ' translate' : ''),
      leaveClass: 'animate__animated animate__zoomOut animate__faster' + (this.boxCenter ? ' translate' : ''),
    }
  },
  methods: {
    toggleFullScreen() {
      if (!this.showFullScreen)
        return
      this.fullScreenFlag = !this.fullScreenFlag;
      if (this.fullScreenFlag) {
        if (this.draggable) {
          //禁止拖动
          this.draggableFlag = false;
          this.draggableDom?.setPause(true);
          const el = this.$el as HTMLElement;
          const style = getComputedStyle(el);
          //记录原始位置
          const parentStyle = getComputedStyle(el.offsetParent!);
          //记录并设置高度，原高度为undefined
          this.originalHeight = Number(style.height.slice(0, -2)) / Number(parentStyle.height.slice(0, -2)) * 100 + '%';
          this.originalWidth = Number(style.width.slice(0, -2)) / Number(parentStyle.width.slice(0, -2)) * 100 + '%';
          this.originalX = el.style.left;
          this.originalY = el.style.top;
          el.style.height = this.originalHeight;
          el.style.width = this.originalWidth;
        }
      } else {
        //允许拖动
        if (this.draggable) {
          this.draggableFlag = true;
          this.draggableDom?.setPause(false);
        }
      }
      this.setSize();
    },
    setSize() {
      const style = (this.$el as HTMLElement).style;
      if (this.fullScreenFlag) {
        gsap.to(style, {
          duration: 0.5,
          ease: 'power1.out',
          width: '100%',
          height: '100%',
          left: this.boxCenter ? '50%' : '0%',
          top: this.boxCenter ? '50%' : '0%'
        }).then(this.sizeChange);
      } else {
        gsap.to(style, {
          duration: 0.5,
          ease: 'power1.in',
          width: this.originalWidth,
          height: this.originalHeight,
          left: this.originalX,
          top: this.originalY
        }).then(this.sizeChange);
      }
    },
    confirm() {
      this.$emit('confirm');
    },
    sizeChange() {
      this.$emit('sizeChange');
    },
    initSize(): void {
      if (this.draggableDom) {
        const el = this.$el as HTMLElement;
        this.draggableDom.setPercentStyle(el);
        el.style.bottom = 'unset';
        el.style.right = 'unset';
      }
    }
  }
})

class DraggableDom {
  readonly #triggerDom: HTMLElement
  readonly #mouseDown: (ev: MouseEvent) => void
  readonly #mouseMove: (ev: MouseEvent) => void
  readonly #mouseUp: () => void
  #clickX = 0
  #clickY = 0
  //点下去的原点
  #originalX = 0
  #originalY = 0
  #minX = 0
  #maxX = 0
  #minY = 0
  #maxY = 0
  #pauseFlag = false

  constructor(dom: HTMLElement, triggerDom: HTMLElement, boxCenter: boolean) {
    this.#triggerDom = triggerDom;
    this.#mouseDown = (ev) => {
      if (this.#pauseFlag)
        return;
      //点击放大和关闭按钮取消拖拽
      if ((ev.target as HTMLElement).tagName === 'I')
        return;
      //记录点击起点
      this.#clickX = ev.screenX;
      this.#clickY = ev.screenY;
      //记录当前元素信息
      const style = getComputedStyle(dom);
      this.setPercentStyle(dom);
      this.#originalX = Number(style.left.slice(0, -2));
      this.#originalY = Number(style.top.slice(0, -2));
      const width = Number(style.width.slice(0, -2));
      const height = Number(style.height.slice(0, -2));
      this.#minX = boxCenter ? Math.floor(width / 2) : 0;
      this.#minY = boxCenter ? Math.floor(height / 2) : 0;
      //记录父元素信息
      const parentStyle = getComputedStyle(dom.offsetParent!);
      const parentWidth = Number(parentStyle.width.slice(0, -2));
      const parentHeight = Number(parentStyle.height.slice(0, -2));
      this.#maxX = parentWidth - width + this.#minX - 1;
      this.#maxY = parentHeight - height + this.#minY - 1;
      document.addEventListener('mousemove', this.#mouseMove);
      document.addEventListener('mouseup', this.#mouseUp)
    }
    this.#mouseMove = (ev) => {
      const offsetX = ev.screenX - this.#clickX;
      const nextX = this.#originalX + offsetX;
      if (nextX < this.#minX)
        dom.style.left = this.#minX + 'px';
      else if (nextX > this.#maxX) {
        dom.style.left = this.#maxX + 'px';
      } else {
        dom.style.left = nextX + 'px';
      }
      const offsetY = ev.screenY - this.#clickY;
      const nextY = this.#originalY + offsetY;
      if (nextY < this.#minY)
        dom.style.top = this.#minY + 'px';
      else if (nextY > this.#maxY)
        dom.style.top = this.#maxY + 'px';
      else
        dom.style.top = nextY + 'px';
    }
    this.#mouseUp = () => {
      this.setPercentStyle(dom);
      document.removeEventListener('mousemove', this.#mouseMove);
      document.removeEventListener('mouseup', this.#mouseUp);
    }
  }

  //按百分比形式设置左和顶
  setPercentStyle(dom: HTMLElement) {
    //还原百分比形式
    if (dom.offsetParent) {
      const parentStyle = getComputedStyle(dom.offsetParent);
      const style = getComputedStyle(dom);
      dom.style.left = Number(style.left.slice(0, -2)) / Number(parentStyle.width.slice(0, -2)) * 100 + '%';
      dom.style.top = Number(style.top.slice(0, -2)) / Number(parentStyle.height.slice(0, -2)) * 100 + '%';
    }
  }

  setPause(value: boolean) {
    this.#pauseFlag = value;
  }

  start() {
    this.#triggerDom.addEventListener('mousedown', this.#mouseDown);
  }

  stop() {
    this.#triggerDom.removeEventListener('mousedown', this.#mouseDown);
    this.#mouseUp();
  }
}
